package com.zlp.demo.v1.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.socket.SocketUtil;
import com.zlp.demo.v1.entity.UserInfo;
import com.zlp.demo.v1.entity.UserInfo.OrderInfo;
import com.zlp.demo.v1.entity.UserInfo.User;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class UserService {


    @Autowired
    private RemoteService remoteService;

    private static volatile Integer sum_size = 0;


    /**
     * 获取用户详情信息
     *
     * @param userId
     * @date: 2022/3/2 13:42
     * @return: com.zlp.demo.v1.entity.UserInfo
     */
    @SneakyThrows
    public UserInfo getUserOrderInfo(Long userId) {
        UserInfo userInfo = new UserInfo();
        // 模拟远程调用>获取用户信息
        UserInfo.User user = new User();
        user.setUserId(userId);
        user.setUsername("zouLiPing");
        user.setAddress("浦东新区");
        userInfo.setUser(user);
        // 模拟远程调用>获取订单信息
        UserInfo.OrderInfo order = new OrderInfo();
        order.setOrderId(new Random(10010010).nextLong());
        order.setProjectName("商品" + new Random(2001010).nextLong());
        order.setOrderTime(remoteService.getDateTime());
        userInfo.setOrderInfo(order);
//        Thread.sleep(100);
        return userInfo;
    }


    /**
     * 获取用户详情信息
     *
     * @param userId
     * @date: 2022/3/2 13:42
     * @return: com.zlp.demo.v1.entity.UserInfo
     */
    public UserInfo getUserInfo(Long userId) {
        long statr = System.currentTimeMillis();
        UserInfo userInfo = new UserInfo();
        // 模拟远程调用>获取用户信息
        UserInfo.User user = remoteService.getUser(userId);
        userInfo.setUser(user);
        // 模拟远程调用>获取订单信息
        UserInfo.OrderInfo order = remoteService.getOrder(userId);
        userInfo.setOrderInfo(order);
        System.out.println(String.format("方法执行耗时%d", System.currentTimeMillis() - statr));
        return userInfo;
    }


    @SneakyThrows
    public UserInfo getUserInfoFutureAsync(Long userId) {

        long statr = System.currentTimeMillis();
        FutureTask<UserInfo.User> userFuture = new FutureTask<>(() -> {
            User user = remoteService.getUser(userId);
            return user;
        });
        FutureTask<UserInfo.OrderInfo> oderFuture = new FutureTask<>(() -> {
            UserInfo.OrderInfo order = remoteService.getOrder(userId);
            return order;
        });

        new Thread(userFuture).start();
        new Thread(oderFuture).start();
        UserInfo userInfo = new UserInfo();
        userInfo.setUser(userFuture.get());
        userInfo.setOrderInfo(oderFuture.get());
        System.out.println(String.format("方法执行耗时%d", System.currentTimeMillis() - statr));
        return userInfo;
    }

    @SneakyThrows
    public UserInfo getUserInfoCompletableFuture(Long userId) {

        long statr = System.currentTimeMillis();
        UserInfo userInfo = new UserInfo();
        CompletableFuture<Void> userFuture = CompletableFuture.runAsync(() -> {
            User user = remoteService.getUser(userId);
            userInfo.setUser(user);
        });

        CompletableFuture<Void> orderFuture = CompletableFuture.runAsync(() -> {
            UserInfo.OrderInfo order = remoteService.getOrder(userId);
            userInfo.setOrderInfo(order);
        });
        // 全部执行完成一起提交
        CompletableFuture.allOf(userFuture, orderFuture).get();
        System.out.println(String.format("方法执行耗时%d", System.currentTimeMillis() - statr));
        return userInfo;
    }

    /**
     * 阻塞线程安全队列
     */
    LinkedBlockingQueue<Request> queue = new LinkedBlockingQueue();

    @SneakyThrows
    public UserInfo getUserOrderBatch(Long userId) {

        CompletableFuture<UserInfo> future = new CompletableFuture();
        String serialNo = UUID.randomUUID().toString();
        Request request = new Request();
        request.setSerialNo(serialNo);
        request.setUserId(userId);
        request.setFuture(future);
        queue.add(request);
        return future.get();
    }

    @PostConstruct
    public void doBusiness() {
        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        executorService.scheduleAtFixedRate(new Runnable() {
            @SneakyThrows
            @Override
            public void run() {
                int size = queue.size();
                // 如果队列中没有任务之间返回
                if (size == 0) {
                    return;
                }
                List<UserReq> userReqList = new ArrayList<>();
                List<Request> futureList = new ArrayList<>();
                for (int i = 0; i < size; i++) {
                    Request request = queue.poll();
                    String serialNo = request.getSerialNo();
                    Long userId = request.userId;
                    userReqList.add(new UserReq(serialNo, userId));
                    futureList.add(request);
                }

                // 批量调用后台方法
                List<UserInfo> userInfoList = getUserInfoBatch(userReqList);
                System.out.println(String.format("批量执行条数size=%d,总体条数sum_size=%d",userReqList.size(),sum_size += userReqList.size()));
                for (UserInfo response : userInfoList) {
                    Map<String, Request> mapRequest = futureList.stream().collect(Collectors.toMap(Request::getSerialNo, Function.identity(), (key1, key2) -> key2));
                    String serialNo = response.getSerialNo();
                    if (mapRequest.containsKey(serialNo)) {
                        Request request = mapRequest.get(serialNo);
                        response.setSerialNo(serialNo);
                        request.getFuture().complete(response);
                        break;
                    }
                }


            }

        }, 100, 10, TimeUnit.MILLISECONDS);
    }

    private List<UserInfo> getUserInfoBatch(List<UserReq> userReqList) {

        List<UserInfo> userInfoList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(userReqList)) {
            for (UserReq userReq : userReqList) {
                UserInfo userOrderInfo = this.getUserOrderInfo(userReq.getUserId());
                userOrderInfo.setSerialNo(userReq.serialNo);
                userInfoList.add(userOrderInfo);
            }
        }
        return userInfoList;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    class UserReq {
        /**
         * 请求和响应的唯一标识
         */
        private String serialNo;
        /**
         * 用户ID
         */
        private Long userId;


    }

    @Data
    class Request {

        /**
         * 请求和响应的唯一标识
         */
        private String serialNo;
        /**
         * 用户ID
         */
        private Long userId;
        /**
         * 异步执行调用任务
         */
        private CompletableFuture<UserInfo> future;

    }

}
